<html>
<head>
  <title>python 函数</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="Evernote Windows/307027 (zh-CN, DDL); Windows/6.1.0 (Win32);"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="632"/>
<h1>python 函数</h1>

<div>
<span><div><div><div style="text-align: center;">        <font style="font-size: 24pt;"><span style="font-size: 24pt; color: rgb(28, 51, 135); font-weight: bold;">函数</span></font></div><div>        写计算机程序也是一样，函数就是最基本的一种代码抽象的方式。<span style="line-height: 1.45;">Python不但能非常灵活地定义函数，而且本身内置了很多有用的函数，可以直接调用。</span></div><div><br/></div><div><span style="font-size: 18pt; color: rgb(28, 51, 135);">调用函数</span></div><div>        Python<font style="font-size: 12pt;"><span style="font-size: 12pt; color: rgb(227, 0, 0); font-weight: bold; text-decoration: underline;">内置了很多有用的函数</span></font>，我们可以直接调用。</div><div>要调用一个函数，需要知道<span style="color: rgb(255, 0, 0); font-weight: bold;">函数</span>的<span style="color: rgb(255, 0, 0); font-weight: bold;">名称</span>和<span style="color: rgb(255, 0, 0); font-weight: bold;">参数</span>，比如求绝对值的函数 abs，它接收一个参数。</div><div>可以直接从Python的官方网站查看文档：</div><div><a href="http://docs.python.org/2/library/functions.html#abs">http://docs.python.org/2/library/functions.html#abs</a></div><div><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 279px;"></col><col style="width: 275px;"></col></colgroup><tbody><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;">内置函数名</td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div>说明</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div><span style="color: rgb(255, 0, 0);">help()</span></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div>交互式命令行</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div>abs()</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div>绝对值</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div> <span style="color: rgb(255, 0, 0);">cmp(x, y)</span></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div>如果 <span style="font-weight: bold;">x&lt;y</span>，返回 <span style="font-weight: bold;">-1</span>，如果 <span style="font-weight: bold;">x==y</span>，返回 <span style="font-weight: bold;">0</span>，如果 <span style="font-weight: bold;">x&gt;y</span>，返回 <span style="font-weight: bold;">1</span></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div><span style="color: rgb(255, 0, 0);">int()</span></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div>数据类型转换函数，可以把其他数据类型转换为整数</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div><span style="color: rgb(255, 0, 0);">str()</span></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div>把其他类型转换成 str</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div>sum()</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div>range()</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div>可以创建一个数列：</div><div>&gt;&gt;&gt; range(1, 101)</div><div>[1, 2, 3, ..., 100]</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div>enumerate()</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div>可以在for循环中同时绑定索引index和元素name</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div>zip()</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div>把两个 list 变成一个 list</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div>capitalize() </div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div>首字母大写，其余全部小写</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div>map()</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div>reduce()</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div>filter()</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div><br/></div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 279px; padding: 8px;"><div> <span style="font-weight: bold;">sorted()</span></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 275px; padding: 8px;"><div><br/></div></td></tr></tbody></table><div><br/></div></div><h2><span style="font-size: 18pt; color: rgb(28, 51, 135); font-weight: normal;">编写函数</span></h2><div>        定义一个函数要使用 <span style="color: rgb(255, 0, 0); font-weight: bold;">def</span> 语句，依次写出<span style="color: rgb(255, 0, 0);">函数名</span>、<span style="color: rgb(255, 0, 0);">括号</span>、括号中的<span style="color: rgb(255, 0, 0);">参数</span>和<span style="color: rgb(255, 0, 0);">冒号:</span>，然后，在缩进块中编写函数体，函数的返回值用 <span style="color: rgb(255, 0, 0);">return</span><span style="color: rgb(255, 0, 0); font-weight: bold;"> </span>语句返回</div><div><br/></div><h2><span style="font-size: 18pt; color: rgb(28, 51, 135); font-weight: normal;">函数之返回多值</span></h2><div><span style="color: rgb(255, 0, 0); font-weight: bold;"># math</span>包提供了<span style="font-weight: bold;">sin()</span>和 <span style="font-weight: bold;">cos()</span>函数，我们先用<span style="color: rgb(255, 0, 0);">import</span>引用它：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">import math</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def move(x, y, step, angle):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    nx = x + step * math.cos(angle)</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    ny = y - step * math.sin(angle)</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    return nx, ny</span></div></div><div>Python函数返回的仍然是单一值：用print打印返回结果，原来返回值是一个<span style="font-weight: bold;">tuple</span>！</div><div>但是，在语法上，返回一个tuple可以省略括号，而多个变量可以同时接收一个tuple，按位置赋给对应的值，所以，<span style="font-weight: bold;">Python的函数</span>返回多值其实就是<span style="font-weight: bold;">返回一个tuple</span>，但写起来更方便。</div><div><br/></div><h2><span style="font-size: 18pt; color: rgb(28, 51, 135); font-weight: normal;">递归函数</span></h2><div>在函数内部，可以调用其他函数。如果一个函数在内部调用自身本身，这个函数就是递归函数。</div><div>计算阶乘 <span style="font-weight: bold;">n! = 1 * 2 * 3 * ... * n</span>，用函数 <span style="font-weight: bold;">fact(n)</span>表示，可以看出：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">fact(n) = n! = 1 * 2 * 3 * ... * (n-1) * n = (n-1)! * n = fact(n-1) * n</span></div></div><div>所以，<span style="font-weight: bold;">fact(n)</span>可以表示为 <span style="font-weight: bold;">n * fact(n-1)</span>，只有n=1时需要特殊处理。</div><div>于是，fact(n)用递归的方式写出来就是：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def fact(n):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    if n==1:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        return 1</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    return n * fact(n - 1)</span></div></div><div><span style="color: rgb(255, 0, 0);">使用递归函数需要注意防止栈溢出</span>。在计算机中，函数调用是通过栈（stack）这种数据结构实现的，每当进入一个函数调用，栈就会加一层栈帧，每当函数返回，栈就会减一层栈帧。由于栈的大小不是无限的，所以，递归调用的次数过多，会导致栈溢出。</div><div><br/></div><h2><span style="font-size: 18pt; color: rgb(28, 51, 135); font-weight: normal;">定义默认参数</span></h2><div>定义函数的时候，还可以有默认参数。</div><div>假设计算平方的次数最多，我们就可以把 n 的默认值设定为 2：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def power(x, n=2):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    s = 1</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    while n &gt; 0:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        n = n - 1</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        s = s * x</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    return s</span></div></div><div>由于函数的参数按从左到右的顺序匹配，所以<span style="font-weight: bold;">默认参数只能定义在必需参数的后面：</span></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(0, 128, 0); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;"># OK:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(0, 128, 0); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def fn1(a, b=1, c=2):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(0, 128, 0); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    pass</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(0, 128, 0); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;"># Error:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(0, 128, 0); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def fn2(a=1, b):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(0, 128, 0); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    pass</span></div></div><div><br/></div><h2><span style="font-size: 18pt; color: rgb(28, 51, 135); font-weight: normal;">定义可变参数</span></h2><div>如果想让一个函数能接受任意个参数，我们就可以定义一个可变参数：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(255, 0, 0); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def fn(*args):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(255, 0, 0); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    print args</span></div></div><div>可变参数的名字前面有个 <span style="color: rgb(255, 0, 0); font-weight: bold;">* </span>号，我们可以传入0个、1个或多个参数给可变参数：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">&gt;&gt;&gt; fn()</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">()</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">&gt;&gt;&gt; fn('a')</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">('a',)</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">&gt;&gt;&gt; fn('a', 'b')</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">('a', 'b')</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">&gt;&gt;&gt; fn('a', 'b', 'c')</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">('a', 'b', 'c')</span></div></div><div>Python解释器会把传入的一组参数组装成一个tuple传递给可变参数，因此，在函数内部，直接把变量 <span style="color: rgb(255, 0, 0);">args</span> 看成一个 <span style="color: rgb(255, 0, 0);">tuple </span>就好了。</div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div style="text-align: center;"><font style="font-size: 24pt;"><span style="font-size: 24pt; color: rgb(28, 51, 135); font-weight: bold;">函数式编程</span></font></div><div>        函数式编程 Functional Programming，函数式编程：不需要变量，没有副作用，支持高阶。</div><div>python支持的函数式编程</div><div><ul><li><span style="line-height: 1.45;">1.不是纯函数式编程：允许有变量</span></li><li><span style="line-height: 1.45;">2.支持高阶函数：函数可以作为变量传入</span></li><li><span style="line-height: 1.45;">3.支持闭包：有闭包就能返回函数</span></li><li><span style="line-height: 1.45;">4.有限度的支持匿名函数</span></li></ul></div><div><br/></div><div><span style="font-size: 18pt; color: rgb(28, 51, 135);">高阶函数</span></div><div><ul><li>变量可以指向函数，直接调用变量和调用函数效果是一样的。</li></ul><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><font style="font-size: 12pt;"><span style="background-color: rgb(251, 250, 248); font-size: 12pt; color: rgb(51, 51, 51); font-family: Monaco; font-weight: bold;">函数名其实也是一种指向函数的变量，名字是约定好的，不轻易更改。</span></font></div></div></div><div><br/></div><div><ul><li>高阶函数：<font style="font-size: 12pt;"><span style="font-size: 12pt; color: rgb(173, 0, 0); font-weight: bold; text-decoration: underline;">能接受函数做参数的函数</span></font></li></ul></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><font style="font-size: 12pt;"><span style="background-color: rgb(251, 250, 248); font-size: 12pt; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-weight: bold;">-变量可以指向函数</span></font></div><div><font style="font-size: 12pt;"><span style="background-color: rgb(251, 250, 248); font-size: 12pt; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-weight: bold;">-函数的参数可以接受变量</span></font></div><div><font style="font-size: 12pt;"><span style="background-color: rgb(251, 250, 248); font-size: 12pt; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-weight: bold;">-一个函数可以接受另一个函数作为参数</span></font></div></div><div><br/></div><div><span style="font-size: 18pt; color: rgb(28, 51, 135);">一个简单的高阶函数：</span></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">def add(x, y, f):</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">        return f(x) + f(y)</span></div></div><div>如果传入abs作为参数f的值：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">add(-5, 9, abs)</span></div></div><div style="margin-top: 1em; margin-bottom: 1em;">根据函数的定义，函数执行的代码实际上是：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">abs(-5) + abs(9)</span></div></div><div>由于参数 x, y 和 f 都可以任意传入，如果 f 传入其他函数，就可以得到不同的返回值。</div><div><br/></div><div><span style="font-size: 18pt; color: rgb(28, 51, 135);">map()函数</span></div></div><div><span style="font-weight: bold;">        map()</span>是 Python 内置的高阶函数，它接收一个<span style="font-weight: bold;">函数 f</span> 和一个 <span style="font-weight: bold;">list</span>，并通过把函数 f 依次作用在 list 的每个元素上，得到一个新的 list 并返回。</div><div>        如果希望把list的每个元素都作平方，就可以用map()函数：</div><div>因此，我们只需要传入函数f(x)=x*x，就可以利用map()函数完成这个计算：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def f(x):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    return x*x</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])</span></div></div><div style="margin-top: 1em; margin-bottom: 1em;"><span style="font-weight: bold;">输出结果：</span></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">[1, 4, 9, 10, 25, 36, 49, 64, 81]</span></div></div><div><span style="font-weight: bold;">注意：</span>map()函数不改变原有的 list，而是<span style="color: rgb(173, 0, 0); text-decoration: underline;">返回一个新的 list</span>。</div><div style="margin-top: 1em; margin-bottom: 1em;"><span style="font-size: 13px; line-height: 1.6em;">利用map()函数，可以把一个 list 转换为另一个 list，只需要传入转换函数。</span></div><div><span style="font-size: 13px; line-height: 1.6em;">由于list包含的元素可以是任何类型，因此，</span><font style="font-size: 12pt;"><span style="font-size: 12pt; color: rgb(173, 0, 0); line-height: 1.6em; text-decoration: underline;">map() 不仅仅可以处理只包含数值的 list，事实上它可以处理包含任意类型的 list，只要传入的函数f可以处理这种数据类型。</span></font></div><div><br/></div><div><span style="font-size: 18pt; color: rgb(28, 51, 135);">reduce()函数</span></div><div><span style="font-weight: bold;">        reduce()</span>函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似，<span style="font-weight: bold;">一个函数 f，一个list</span>，但行为和 map()不同，reduce()传入的函数 f 必须接收两个参数，reduce()对list的每个元素反复调用函数f，并返回最终结果值。</div><div><br/></div><div><br/></div><div><br/></div><div><span style="font-size: 18pt; color: rgb(28, 51, 135);">filter()函数</span></div><div>        filter()函数接收一个<span style="font-weight: bold;">函数 f </span>和一个<span style="font-weight: bold;">list</span>，这个函数 f 的作用是对每个元素进行判断，返回 True或 False，<span style="font-weight: bold;">filter()根据判断结果自动过滤掉不符合条件的元素，返回由符合条件元素组成的新list。</span></div><div>例如，要从一个list [1, 4, 6, 7, 9, 12, 17]中删除偶数，保留奇数，首先，要编写一个判断奇数的函数：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def is_odd(x):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    return x % 2 == 1</span></div></div><div style="margin-top: 1em; margin-bottom: 1em;">然后，利用filter()过滤掉偶数：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">filter(is_odd, [1, 4, 6, 7, 9, 12, 17])</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">结果：[1, 7, 9, 17]</span></div></div><div><br/></div><div> <span style="font-size: 18pt; color: rgb(28, 51, 135);">sorted()函数</span></div><div><span style="font-weight: bold;">        sorted()</span>也是一个高阶函数，它可以接收一个比较函数来实现自定义排序，比较函数的定义是，传入两个待比较的元素 x, y，<span style="font-weight: bold;">如果 x 应该排在 y 的前面，返回 -1，如果 x 应该排在 y 的后面，返回 1。如果 x 和 y 相等，返回 0。</span></div><div><br/></div><div><br/></div><h2><span style="font-size: 18pt; color: rgb(28, 51, 135); font-weight: normal;">返回函数</span></h2><div>Python的函数不但可以返回int、str、list、dict等数据类型，还可以返回函数！</div><div>例如，定义一个函数 f()，我们让它返回一个函数 g，可以这样写：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def f():</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    print 'call f()...'</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    # 定义函数g:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    def g():</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        print 'call g()...'</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    # 返回函数g:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    return g</span></div></div><div>        仔细观察上面的函数定义，我们在函数 f 内部又定义了一个函数 g。由于函数 g 也是一个对象，函数名 g 就是指向函数 g 的变量，所以，最外层函数 f 可以返回变量 g，也就是函数 g 本身。</div><div>但是，如果返回一个函数，就可以“延迟计算”：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def calc_sum(lst):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    def lazy_sum():</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        return sum(lst)</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    return lazy_sum</span></div></div><div style="margin-top: 1em; margin-bottom: 1em;"># 调用calc_sum()并没有计算出结果，而是返回函数:</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">&gt;&gt;&gt; f = calc_sum([1, 2, 3, 4])</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">&gt;&gt;&gt; f</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">&lt;function lazy_sum at 0x1037bfaa0&gt;</span></div></div><div style="margin-top: 1em; margin-bottom: 1em;"># 对返回的函数进行调用时，才计算出结果:</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">&gt;&gt;&gt; f</span><font style="font-size: 12pt;"><span style="background-color: rgb(251, 250, 248); font-size: 12pt; color: rgb(227, 0, 0); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-weight: bold;">()</span></font></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">10</span></div></div><div><br/></div><div><br/></div><h2><span style="font-size: 18pt; color: rgb(173, 0, 0);">闭包</span></h2><div>在函数内部定义的函数和外部定义的函数是一样的，只是他们无法被外部访问</div><div>将 <span style="font-weight: bold;">g</span> 的定义移入函数 <span style="font-weight: bold;">f</span> 内部，防止其他代码调用 <span style="font-weight: bold;">g</span>：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def f():</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    print 'f()...'</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    def g():</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        print 'g()...'</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    return g</span></div></div><div>但是，考察上一小节定义的 <span style="font-weight: bold;">calc_sum</span> 函数：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def calc_sum(lst):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    def lazy_sum():</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        return sum(lst)</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    return lazy_sum</span></div></div><div style="margin-top: 1em; margin-bottom: 1em;"><span style="font-weight: bold;">注意:</span> 发现没法把 <span style="font-weight: bold;">lazy_sum</span> 移到 <span style="font-weight: bold;">calc_sum</span> 的外部，因为它引用了 <span style="font-weight: bold;">calc_sum</span> 的参数 <span style="font-weight: bold;">lst</span>。</div><div>        像这种内层函数引用了<font style="font-size: 12pt;"><span style="font-size: 12pt; color: rgb(173, 0, 0); font-weight: bold; text-decoration: underline;">外层函数的变量（参数也算变量）</span></font>，然后返回内层函数的情况，称为<span style="font-weight: bold;">闭包（Closure）</span>。</div><div><span style="font-weight: bold;">        闭包的特点</span>是返回的函数还引用了外层函数的局部变量，所以，要正确使用闭包，就要确保引用的局部变量在函数返回后不能变。因此，返回函数不要引用任何循环变量，或者后续会发生变化的变量。</div><div><br/></div><div><br/></div><h2><span style="font-size: 18pt; color: rgb(28, 51, 135); font-weight: normal;">匿名函数</span></h2><div>在Python中，对匿名函数提供了有限支持。</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">&gt;&gt;&gt; map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[1, 4, 9, 16, 25, 36, 49, 64, 81]</span></div></div><div><br/></div><div><span style="color: rgb(255, 0, 0);">关键字lambda </span>表示匿名函数，冒号前面的 <span style="color: rgb(255, 0, 0);">x 表示函数参数。</span></div><div>匿名函数有个限制，就是<span style="font-weight: bold;">只能有一个表达式</span>，<span style="font-weight: bold;">不写return</span>，返回值就是该表达式的结果。</div><div style="margin-top: 1em; margin-bottom: 1em;">使用匿名函数，可以不必定义函数名，直接创建一个函数对象，很多时候可以简化代码：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">&gt;&gt;&gt; sorted([1, 3, 9, 5, 0], lambda x,y: -cmp(x,y))</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">[9, 5, 3, 1, 0]</span></div></div><div><br/></div><div> </div><div><br/></div><div><br/></div><div><br/></div><div style="text-align: center;"><div><br/></div></div><div style="text-align: center;"><font color="#1C3387" style="font-size: 24pt;"><span style="color: rgb(28, 51, 135); font-size: 24pt; font-weight: bold;">decorator装饰器</span></font></div><div style="text-align: center;"><br/></div><div>通过高阶函数返回新函数</div><div><img src="python 函数_files/Image.jpg" type="image/jpeg" data-filename="Image.jpg" width="449"/></div><div><img src="python 函数_files/Image [1].jpg" type="image/jpeg" data-filename="Image.jpg" width="444"/></div><div><img src="python 函数_files/Image [2].jpg" type="image/jpeg" data-filename="Image.jpg" width="443"/></div><div>Python的 <span style="color: rgb(255, 0, 0);">decorator<span style="color: rgb(255, 0, 0); text-decoration: underline;"> </span></span><span style="text-decoration: underline;">本质上就是一个高阶函数</span>，它接收一个函数作为参数，然后，返回一个新函数。</div><div style="margin-top: 1em; margin-bottom: 1em;">使用 decorator 用Python提供的 <span style="color: rgb(255, 0, 0);">@</span> 语法，这样可以避免手动编写 <span style="color: rgb(255, 0, 0);">f = decorate(f) </span>这样的代码。</div><div><font color="#AD0000" style="font-size: 14pt;"><b><span>    <span>    </span></span>装饰器本质上是一个Python函数，它可以让其他函数在不需要做任何代码变动的前提下增加额外功能，装饰器的返回值也是一盒函数对象。</b></font></div><div><font color="#AD0000" style="font-size: 14pt;"><b><span>    <span>    </span></span>它经常用于有切面需求的场景，比如：插入日志、性能测试、事务处理、缓存、权限校验等场景。概括的讲，装饰器的作用就是为已经存在的对象添加额外的功能。</b></font></div><div><br/></div><div>例子：</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">def foo():</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    <span>  </span></span>print('i am foo')</span></div></div><div><span>    <span>    </span></span>现在有一个新的需求，希望可以记录下函数的执行日志，于是在代码中添加日志代码：</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">def foo():</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    <span> </span></span>print('i am foo')</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>     logging.info(&quot;foo is running&quot;)</span><br/></span></div></div><div><span>    <span>    </span></span>bar()、bar2()也有类似的需求，怎么做？再写一个logging在bar函数里？这样就造成大量雷同的代码，为了减少重复写代码，我们可以这样做，重新定义一个函数：专门处理日志 ，日志处理完之后再执行真正的业务代码</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>def use_logging(func):</div><div><span>    logging.warn(&quot;%s is running&quot; % func.__name__)</span><br/></div><div><span><span>    func()</span><br/></span></div><div><span><br/></span></div><div><span>def bar():</span></div><div><span><span>    print('i am bar')</span><br/></span></div><div><span><br/></span></div><div><span>use_logging(bar)</span></div></div><div><span>    <span>    </span></span>逻辑上不难理解， 但是这样的话，我们每次都要将一个函数作为参数传递给use_logging函数。且这种方式已经破坏了原有的代码逻辑结构，之前执行业务逻辑时，执行运行bar()，但是现在不得不改成use_logging(bar)。那么有没有更好的方式的呢？当然有，答案就是装饰器。</div><div><br/></div><div><font style="font-size: 18pt; color: rgb(28, 51, 135);">简单装饰器</font></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>def use_logging(func):</div><div><span>    </span><br/></div><div><span><span>    def wrapper(*args, **kwargs):</span><br/></span></div><div><span><span>    <span>    logging.warn(&quot;%s is running&quot; % func.__name__)</span></span><br/></span></div><div><span><span>    <span>    return func(*args, **kwargs)</span></span><br/></span></div><div><span><span>    return wrapper</span><br/></span></div><div><span><br/></span></div><div><span>def bar():</span></div><div><span><span>    print('i am bar')</span><br/></span></div><div><span><br/></span></div><div><span>bar = use_logging(bar)</span></div><div><span>bar()</span></div></div><div>函数use_logging就是装饰器，它把执行真正业务方法的func包裹在函数里面，看起来像bar被use_logging装饰了。在这个例子中，函数进入和退出时 ，被称为一个横切面(Aspect)，这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。</div><div><br/></div><div>@符号是装饰器的语法糖，在定义函数的时候使用，避免再一次赋值操作</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>def use_logging(func):</div><div><span>    </span><br/></div><div><span><span>    def wrapper(*args, **kwargs):</span><br/></span></div><div><span><span>    <span>    logging.warn(&quot;%s is running&quot; % func.__name__)</span></span><br/></span></div><div><span><span>    <span>    return func(*args)</span></span><br/></span></div><div><span><span>    return wrapper</span><br/></span></div><div><span><br/></span></div><div><span>@use_logging</span></div><div><span>def foo():</span></div><div><span><span>    print(&quot;i am foo&quot;)</span><br/></span></div><div><span><br/></span></div><div><span>@use_logging</span></div><div><span>def bar():</span></div><div><span><span>    print(&quot;i am bar&quot;)</span><br/></span></div><div><span><br/></span></div><div><span>bar()</span></div></div><div>装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数，可以被赋值给其他变量，可以作为返回值，可以被定义在另外一个函数内。</div><div><br/></div><div><font style="font-size: 18pt; color: rgb(28, 51, 135);">带参数的装饰器</font></div><div>装饰器还有更大的灵活性，例如带参数的装饰器：在上面的装饰器调用中，比如@use_logging，<font style="color: rgb(173, 0, 0);"><b><u>该装饰器唯一的参数就是执行业务的函数</u></b></font>。装饰器的语法允许我们在调用时，提供其它参数，比如@decorator(a)。</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>def use_logging(level):</div><div><span>    def decorator(func):</span><br/></div><div><span><span>    <span>    def wrapper(*args, **kwargs):</span></span><br/></span></div><div><span><span>    <span>    <span>    if level == &quot;warn&quot;:</span></span></span><br/></span></div><div><span><span>    <span>    <span>    <span>    logging.warn(&quot;%s is running&quot; % func.__name__)</span></span></span></span><br/></span></div><div><span><span>    <span>    <span>    return func(*args)</span></span></span><br/></span></div><div><span><span>    <span>    return wrapper</span></span><br/></span></div><div><span><span>    return decorator</span><br/></span></div><div><span><br/></span></div><div><span>@use_logging(level=&quot;warn&quot;)</span></div><div><span>def foo(name='foo'):</span></div><div><span><span>    print(&quot;i am %s&quot; % name)</span><br/></span></div><div><span><br/></span></div><div><span>foo()</span></div><div><span><br/></span></div></div><div>我们可以将它理解为一个含有参数的闭包。当我 们使用@use_logging(level=&quot;warn&quot;)调用的时候，Python能够发现这一层的封装，并把参数传递到装饰器的环境中。</div><div><br/></div><div><br/></div><div><span style="font-weight: bold;"><font style="font-size: 18pt; color: rgb(28, 51, 135);">类装饰器</font></span></div><div><br/></div><div>相比函数装饰器，类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器还可以依靠类内部的\_\_call\_\_方法，当使用 @ 形式将装饰器附加到函数上时，就会调用此方法。</div><div><br/></div><div><br/></div><div><font style="font-size: 18pt; color: rgb(28, 51, 135);">内置装饰器</font></div><div>@staticmathod、@classmethod、@property</div><div><br/></div><div>装饰器的顺序</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>@a</div><div>@b</div><div>@c</div><div>def f ():</div></div><div><span style="-en-paragraph: true;">等效于</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>f = a(b(c(f)))</div></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><h2><span style="color: rgb(28, 51, 135); font-size: 18pt;">偏函数</span></h2><div><span style="color: rgb(255, 0, 0);">functools.partial</span>就是帮助我们创建一个偏函数的，不需要我们自己定义<span style="color: rgb(255, 0, 0);">int2()</span>，可以直接使用下面的代码创建一个新的函数int2：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">&gt;&gt;&gt; import functools</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">&gt;&gt;&gt; int2 = functools.partial(int, base=2)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">&gt;&gt;&gt; int2('1000000')</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">64</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">&gt;&gt;&gt; int2('1010101')</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">85</span></div></div><div>所以，<span style="color: rgb(255, 0, 0);">functools.partial</span>可以把一个参数多的函数变成一个参数少的新函数，少的参数需要在创建时指定默认值，这样，新函数调用的难度就降低了。</div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div></div><div><br/></div></span>
</div></body></html> 